package paper.http;

import  org.apache.catalina.Context;
import  org.apache.catalina.Host;
import  org.apache.catalina.Engine;
import  org.apache.catalina.startup.Embedded;

import java.io.*;
import java.util.Map;
import java.util.Vector;
import java.util.Iterator;
import java.util.regex.*;
import java.util.Collections;
import java.sql.*;

import javax.servlet.*;
import javax.servlet.http.*;

import paper.db.DB;
import paper.db.Paper;
import paper.db.PDFFile;
import paper.batch.Batch;
import paper.query.QueryBuilder;
import paper.http.Pager;

import paper.db.Tags;
import paper.tags.TagBag;


public class Servlet extends HttpServlet {
    public String name = "blah";
    public static Batch batchProcessor = null;

    public Servlet() {
        if (batchProcessor == null) {
            batchProcessor = new Batch();
        }
    }

	public void init() throws ServletException {
		System.out.println("TestServlet : init");
	}

	public void destroy() {
		System.out.println("TestServlet : destroy");
	}

	public void doPost(HttpServletRequest req, HttpServletResponse res)
		throws IOException, ServletException {
		doGet(req, res);
	}

	public void doGet(HttpServletRequest req, HttpServletResponse res) 
		throws IOException, ServletException {
        String action = req.getPathInfo();
        String userID = null;
        String email = null;
        String realEmail = null;
        String cookie = null;
        Cookie[] cookies = req.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                if (cookies[i].getName().equals("email")) {
                    email = cookies[i].getValue();
                } else if (cookies[i].getName().equals("auth")) {
                    cookie = cookies[i].getValue();
                }
            }
            if (email != null && cookie != null) {
                userID = Authorisation.userIDOfCookie(email, cookie);
            } 
        }
        if (userID != null) {
            realEmail = email;
        }
       
        if (action != null && action.equals("/doupload")) {
            if (userID == null) {
                res.sendRedirect("/login?onwards=doupload");
                return;
            }
            doUpload(req, res, userID);
            return;
        }
        Map<String,String[]> parameters = req.getParameterMap();
        if (action!=null && action.equals("/show")) {
            res.setContentType("text/html");
            show(res.getWriter(),parameters, realEmail);
        } else if (action != null && action.equals("/text")) {
            showText(res, parameters);
        } else if (action != null && action.equals("/pdf")) {
            showPDF(res, parameters);
        } else if(action!=null && action.equals("/img")){
            showImg(res,parameters);
        } else if(action!=null && action.equals("/tag")){
            showTag(res,res.getWriter(),parameters,userID, cookie, realEmail);
        } else if(action!=null && action.equals("/js")){
            showJs(res, parameters);
        } else if (action != null && action.equals("/reprocess")) {
            doReprocess(res, parameters);
        } else if (action != null && action.equals("/data")) {
            res.setContentType("text/html");
            showData(res.getWriter(),parameters, realEmail);
        } else if (action != null && action.equals("/citations")) {
            res.setContentType("text/html");
            showCitations(res.getWriter(),parameters, realEmail);
        } else if (action != null && action.equals("/home")) {
            if (userID == null) {
                res.sendRedirect("/login?onwards=home");
                return;
            }
            res.setContentType("text/html");
            showHome(res.getWriter(),parameters, userID, cookie, realEmail);
        } else if (action != null && action.equals("/search")) {
            res.setContentType("text/html");
            showSearch(res.getWriter(),parameters, realEmail);
        } else if (action != null && action.equals("/author")) {
            res.setContentType("text/html");
            showAuthor(res.getWriter(),parameters, realEmail);
        } else if (action != null && action.equals("/allauthors")) {
            res.setContentType("text/html");
            showAllAuthors(res.getWriter(),parameters, realEmail);
        } else if (action != null && action.equals("/")) {
            res.setContentType("text/html");
            showWelcome(res.getWriter(), userID != null);
        } else if (action != null && action.equals("/dourl")) {
            if (userID == null) {
                res.sendRedirect("/login?onwards=home");
                return;
            }
            doURL(userID, res, parameters);
        } else if (action != null && action.equals("/login")) {
            showLogin(res,parameters, email);
        } else if (action != null && action.equals("/registermail")) {
            showRegisterMail(req, res, parameters);
        } else if (action != null && action.equals("/registerupdate")) {
            showRegisterUpdate(res, parameters);
        } else if (action != null && action.equals("/register")) {
            res.setContentType("text/html");
            showRegister(res.getWriter(), parameters);
        } else if (action != null && action.equals("/upload")) {
            res.setContentType("text/html");
            if (userID == null) {
                res.sendRedirect("/login?onwards=upload");
                return;
            }
            showUpload(res.getWriter(), realEmail);
        } else {
            PrintWriter out = res.getWriter();
            doHTMLHeader(out,"Unknown request " + action);
            doPageHeader(out,"", "Home");
            out.println("Not sure what " + action + " " + req.getQueryString() + " does");
            doTrailer(out);
        }
    }
    
    private void doHTMLHeader(PrintWriter out, String title) {
        doHTMLHeader(out, title, "", "");
    }
    
    private void doHTMLHeader(PrintWriter out, String title, String onLoad) {
        doHTMLHeader(out, title, onLoad, "");
    }

    private void doHTMLHeader(PrintWriter out, String title,
                              String onLoad, String header) {
		out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
        out.println("<html>" + header + "<head>");
		out.println("<link type='text/css' rel='stylesheet' href='/lib/m.css' />");
		out.println("<script src='/js' type='text/javascript'></script>");
		out.println("<title>paperBase " + title + "</title></head>");
		out.println("<body onload='" + onLoad + "'>");
    }

    private void doPageHeader(PrintWriter out, String title, String pagetitle, String email) {
        out.print("<div class='top'><form class='head' name='search' action='/search' method='get'><p class='left'>");
        if (pagetitle != null) {
            out.print("<a class='menu' href='/home'>" + pagetitle + "</a>&nbsp;&nbsp;");
        } else {
            out.print("<a class='menu' href='/login'>Login</a>&nbsp;&nbsp;");
        }
        out.print(title);
	if(email!=null){
		out.print(" &nbsp; <i>"+email+"</i>");
	}
	out.print("</p>");
        out.print("<p class='right'>");
        out.print("<input class='head' type='text' size='30' name='query'/>");
        out.print("<input class='button' type='submit' value='search'/>");
        out.print("&nbsp;paperBase v0.1</p></form></div>");
		out.println("<div class='contents'>");
    }

    private void doPageHeader(PrintWriter out, String title, String email) {
        out.print("<div class='top'><form class='head' name='search' action='/search' method='get'><p class='left'>");
        if (email != null) {
            out.print("<a class='menu' href='/home'>" + email + "</a>&nbsp;&nbsp;");
        } else {
            out.print("<a class='menu' href='/login'>Login</a>&nbsp;&nbsp;");
        }
        out.print(title + "</p>");
        out.print("<p class='right'>");
        out.print("<input class='head' type='text' size='30' name='query'/>");
        out.print("<input class='button' type='submit' value='search'/>");
        out.print("&nbsp;paperBase v0.1</p></form></div>");
		out.println("<div class='contents'>");
    }

    private void doTrailer(PrintWriter out) {
		out.println("</div>");
		out.println("</body></html>");
		out.close();
	}


    private void showTag(HttpServletResponse resp, PrintWriter out, Map<String,String[]> args,  String userID, String cookie, String email){
        String meta = "";
        Statement st = null;
        Statement myst = null;
	ResultSet rs=null;
        String noBibliography = "No bibliography found";
        String noCitations= "No bibliography found";
        doHTMLHeader(out, "Home", "", meta);
        doPageHeader(out,"<a class='menu' href='/upload'>Upload papers</a>", "Home",email);
        String id = args.get("id")[0];
        String[] addtags=args.get("addtags");
        String[] deletetag=args.get("deletetagid");
        
        
        
        try {	
            // TODO: Fix this ugly gunk
            st = DB.connection.createStatement();
            if(deletetag!=null){
                if(deletetag.length>0){
                    st.executeUpdate("DELETE FROM tags WHERE paperkey='"+DB.q(id,16)+"' AND userid='"+userID+"' AND tagid='"+DB.q(deletetag[0],16)+"'");
                }
            }
            if(addtags!=null){
                if(addtags.length>0){
                    String addtag=addtags[0];
                    String[] adder=addtag.split(" ");
                    
                    
                    // make sure these strings actually contain something
                    for(int tmp=0;tmp<adder.length;tmp++){
                        //adder[tmp]=QueryBuilder.trim(adder[tmp]);
                        adder[tmp]=QueryBuilder.tagCleanUp(adder[tmp]);
                        if(adder[tmp].length()>0){
                            rs=st.executeQuery("SELECT tag FROM tags WHERE paperkey='"+DB.q(id,16)+"' AND userid='"+userID+"' AND tag='"+DB.q(adder[tmp],128)+"'");
                            int count=0;
                            while(rs.next()){
                                count++;
                            }
                            rs.close();
                            if(count<1){
                                st.executeUpdate("INSERT INTO tags (tag, paperkey, userid) values ('"+DB.q(adder[tmp],128)+"', '"+DB.q(id,16)+"', '"+userID+"')");
                            }
                        }
                    }
                }
            }
            String pdfLink = "";
            rs = st.executeQuery("SELECT analysed, md5 FROM pdffiles WHERE paperkey='" + DB.q(id,16) + "'");
            while (rs.next()) {
                boolean analysed = rs.getString(DB.analysed).equals("1");
                pdfLink += "&nbsp;&nbsp;&nbsp;<a href='/pdf?id=" + rs.getString(DB.md5) + "' class='menu'>PDF</a>";
                if (analysed) {
                    pdfLink += "&nbsp;<a href='/data?id=" + rs.getString(DB.md5) + "' class='menu'>Data</a>";
                }
            }
            if (pdfLink.equals("")) {
                pdfLink = "no PDF archived";
                noBibliography = "Paper not in archive - no bibliography";
            }
            rs.close();
            rs = st.executeQuery("SELECT authors FROM authors WHERE paperkey='" + DB.q(id,16) + "' ORDER BY sequence");
            StringBuilder sb = new StringBuilder();
            while (rs.next()) {
                String a = rs.getString(1);
                sb.append("<a href='/author?name=" + a.replaceAll(" ","+") +
                          "'>" + a + "</a>;&nbsp;&nbsp;");
            }
            rs.close();
            rs = st.executeQuery("SELECT authors, email, title, year FROM papers p WHERE key='" + DB.q(id,16) + "'");
            if (!rs.next()) {
                out.println("No such paper");
                doTrailer(out);
                return;
            }
            String title = rs.getString(DB.title);
            if (title.startsWith("MD5: ")) {
                noCitations = "Paper title not established";
            }
            out.println("<div class='addButton'>");
            out.println("<a href='/home?add=" + id + "'>Add to home</a>");
            out.println("<a href='http://www.google.com/search?q=" + title.replaceAll("[ \n]","+") + "'>Google</a></div>");
            out.println("<div class='center'>");
            out.println("<span class='huge'>");
            out.println(title);
            out.println("<br/></span><span class='large'>");
            out.println(sb.length() == 0 ? rs.getString(DB.authors) : sb.toString());
            out.println("<br/></span><span class='large'><tt>");
            out.println(rs.getString(DB.email));
            out.println("</tt><br/></span>");
            out.println(rs.getString(DB.year));
            out.println("</div>");
            rs.close();
            st.close();
        } catch(SQLException e){
            
        }
        out.println("<div class='alignright'>");
        if (cookie != null) {
            // you're logged in, you can edit tags
            // get info for pdf
            out.println("<br/><div class='center' id='magic'><h2>Add tags</h2>"+ // draw out the form
                        "<form name='tags' action='/tag'>"+
                        "<input type='text' name='addtags' size='40'/>"+
                        "<input type='hidden' name='id' value='"+id+"'/>"+
                        "<input type='submit' value='Tag!'/>"+
                        "</form>"+
                        "</div>");
        } else {
            out.println("<br/><div class='centerwarn'>You must <a href='/login'>log in</a> to add tags</div>");
        }
        TagBag myBag=Tags.getPersonalTagBagForPaperkey(id,userID);	
        if(myBag.getSize()>0){
            out.println("<br/><div class='center'>My tags for this file: <span class='tags'>"+
                        myBag.getAll("/tag",id,userID)+
                        "</span></div>");
        } else {
            out.println("<br/><div class='center'>You have no tags for this file.</div>");
        }
        out.println("</div>");
        out.println("<div class='tagcloud'>");
        TagBag theBag=Tags.getTagBagForPaperkey(id,userID);
        if(theBag.getSize()>0){
            out.println("<div class='center'><br/><h2>Public tags for this paper:</h2><br/>"+
                        theBag.getTagCloud()+
                        "</div>");
        } else{
            out.println("<div class='center'><br/>Nobody has tagged this paper</div>");
        }
        TagBag theOtherBag=Tags.getTagBag(); // the big one -- ought to nick the newest tags by date but that would mean having some
        if(theOtherBag.getSize()>0){
            out.println("<div class='center'><br/><h2>Most common tags site-wide:</h2><br/>"+
                        theOtherBag.getTagCloud()+"</div>");
        }
        doTrailer(out);
    }

    private void showJs(HttpServletResponse resp, Map<String,String[]> args) {
	try {
           File inFile = new File("src/scripts.js");
	   if(inFile.exists()){
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inFile));
            OutputStream out = resp.getOutputStream();
            resp.setContentType("text/javascript");
            resp.setContentLength((int)inFile.length());
            BufferedOutputStream bos = new BufferedOutputStream(out);
            byte[] buffer = new byte[16384];
            while (true) {
                int i = bis.read(buffer);
                if (i == -1) {
                    break;
                }
                bos.write(buffer, 0, i);
            }
            bis.close();
            bos.close();
		} else {
			System.err.println("JS File does not exist :-(");
		}
        } catch (Exception e) {
            System.err.println("Couldn't deliver javascript " + e);
        }
	
    }

    private void showImg(HttpServletResponse resp, Map<String,String[]> args) {
	 try {
            String id = args.get("id")[0];
	    File inFile;
	    if(id.substring(id.length()-5,id.length()).equals("thumb")){
            	inFile = PDFFile.getThumbnail(id.substring(0,32));

	    } else {
            	inFile = PDFFile.getImg(id);

	    }	
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inFile));
            OutputStream out = resp.getOutputStream();
            resp.setContentType("image/png");
            //resp.setHeader("Content-Disposition", "attachment; filename=" + id + ".pdf");
            resp.setContentLength((int)inFile.length());
            BufferedOutputStream bos = new BufferedOutputStream(out);
            byte[] buffer = new byte[16384];
            while (true) {
                int i = bis.read(buffer);
                if (i == -1) {
                    break;
                }
                bos.write(buffer, 0, i);
            }
            bis.close();
            bos.close();
        } catch (Exception e) {
            System.err.println("Couldn't deliver image " + e);
        }

    }

    private void showPDF(HttpServletResponse resp, Map<String,String[]> args) {
        try {
            String id = args.get("id")[0];
            File inFile = PDFFile.getFile(id);
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inFile));
            OutputStream out = resp.getOutputStream();
            resp.setContentType("application/pdf");
            resp.setHeader("Content-Disposition", "attachment; filename=" + id + ".pdf");

            resp.setContentLength((int)inFile.length());
            BufferedOutputStream bos = new BufferedOutputStream(out);
            byte[] buffer = new byte[16384];
            while (true) {
                int i = bis.read(buffer);
                if (i == -1) {
                    break;
                }
                bos.write(buffer, 0, i);
            }
            bis.close();
            bos.close();
        } catch (Exception e) {
            System.err.println("Couldn't deliver PDF " + e);
        }
    }

    private void showText(HttpServletResponse resp, Map<String,String[]> args) {
        try {
            String id = args.get("id")[0];
            File inFile = PDFFile.getText(id);
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inFile));
            OutputStream out = resp.getOutputStream();
            resp.setContentType("text/plain");

            resp.setContentLength((int)inFile.length());
            BufferedOutputStream bos = new BufferedOutputStream(out);
            byte[] buffer = new byte[16384];
            while (true) {
                int i = bis.read(buffer);
                if (i == -1) {
                    break;
                }
                bos.write(buffer, 0, i);
            }
            bis.close();
            bos.close();
        } catch (Exception e) {
            System.err.println("Couldn't deliver text " + e);
        }
    }

    private void doReprocess(HttpServletResponse resp,
                             Map<String,String[]> args) throws IOException {
        String id = args.get("id")[0];
        if (id.equals("all")) {
            batchProcessor.addReprocessAll();
            resp.sendRedirect("/home");
        } else {
            batchProcessor.addReprocessMd5(id);
            resp.sendRedirect("/data?id=" + id);
        }
    }

    private void paperListStart(PrintWriter out) {
        out.println("<table>");
    }

    private void paperListHeader(PrintWriter out, String header) {
        out.println("<tr><td colspan='5'><h2>" + header + "</h2></td>");
    }

    private boolean paperListEntry(PrintWriter out, ResultSet rs, boolean extra)
        throws SQLException {
        boolean analysed = true;
        String personalNotes = null;
        String md5     = rs.getString(DB.md5);
        String year    = rs.getString(DB.year);
        String authors = rs.getString(DB.authors);
        String title   = rs.getString(DB.title);
        String key     = rs.getString(DB.key);
        String weight  = rs.getString("weight"); // not a database column
        if (extra) {
            String x = rs.getString(DB.analysed);
            if (x != null && x.equals("0")) {
                analysed = false;
            }
            personalNotes = rs.getString(DB.personalNotes);        
        }
        String md5List = "";
        if (md5 != null) {
            md5List = "<a href='/pdf?id=" + md5 + "'>pdf</a>";
        }
        boolean moreData = true;
        boolean seenAllTags = false;
        TagBag tags = new TagBag();
        do {
            if (!key.equals(rs.getString(DB.key))) {
                break;
            }
            if (md5 != null && !md5.equals(rs.getString(DB.md5))) {
                seenAllTags = true;
                md5 = rs.getString(DB.md5);
                md5List += " <a href='/pdf?id=" + md5 + "'>pdf</a>";
            }
            if (!seenAllTags) {
                tags.addFromResultSet(rs);
            }
            moreData = rs.next();
        } while (moreData);
        out.print("<tr><td class='pdf0'><b>" + md5List + "</b></td>");
        if (analysed) {
            out.print("<td class='year1'>"  + year + "</td>"+
                      "<td class='author2'>" + authors + "</td>" +
                      "<td class='title"+ (personalNotes == null ? "34":"3")+
                      "'><a href='/show?id=" + key + "'>" +
                      "<em>" + title +
                      (weight == null?"":"&nbsp;&nbsp;<span class='relevance'>(" + weight + ")</span>")+
                      "</em>.</a></td>");
        } else {
            // include image
            String addendum="";
            try {
                File myFile=PDFFile.getImg(md5);
                
                File myFile2=PDFFile.getThumbnail(md5);
                if(myFile2.exists()){
                    addendum="<img border='0' src='/img?id="+md5+"-thumb' alt='thumbnail'/>";
                } else {
                    addendum="[View cover; unparseable PDF]";                }
                if(myFile.exists()){
                    addendum="<a href='/img?id="+md5+"'>" + addendum + "</a>";
                } else {
                }
            } catch(Exception e){
                System.err.println("Exception: "+e);
            }
            
            out.print("<td class='none12' colspan='2'></td><td class='title3'>"+addendum+"</td>");
        }

        String previewTags=tags.getPreview();
        if (personalNotes != null) {
            out.print("<td class='notes4'>" + personalNotes);
            if(previewTags!=null){
                out.print("<br/><span class='tags'>"+previewTags+"</span>"+tags.tagControls(key));
            }	
            out.print ("</td>");
        } else if(previewTags!=null){
            out.print("<td class='notes4'><span class='tags'>"+previewTags+"</span>"+tags.tagControls(key));
        } else {
            out.print(tags.tagControls(key));	
        }
        out.println("</tr>");
        return moreData;
    }


    private boolean paperListEntries(PrintWriter out, ResultSet rs, boolean extra)
        throws SQLException {
        if (!rs.next()){
            return false;
        }
        while (paperListEntry(out, rs, extra)) {
            ;
        }
        return true;
    }

    private void paperListComment(PrintWriter out, String comment) {
        out.println("<tr><td></td><td colspan='3'>" + comment + "</td></tr>");
    }

    private void paperListEnd(PrintWriter out) {
        out.println("</table>");
    }

//    long t0, t1, t2;
    private void showQuery(Statement st, PrintWriter out, String query,
                           String theTitle, String none) throws SQLException {
//        t0 = System.currentTimeMillis(); System.out.println("Out: " + (t0-t2));
        ResultSet rs = st.executeQuery(query);
//        t1 = System.currentTimeMillis(); System.out.println("Que: " + (t1-t0));
        paperListHeader(out, theTitle);
        if (!paperListEntries(out, rs, false)) {
            paperListComment(out, none);
        }
//        t2 = System.currentTimeMillis(); System.out.println("Prt: " + (t2-t1));
        rs.close();
    }


    private void show(PrintWriter out, Map<String,String[]> args, String email) {
        String id = args.get("id")[0];
        Statement st = null;
        ResultSet rs = null;
        String noBibliography = "No bibliography found";
        String noCitations = "None found";

        doHTMLHeader(out,id);
        try {
            String pdfLink = "";
            st = DB.connection.createStatement();
            rs = st.executeQuery("SELECT analysed, md5 FROM pdffiles WHERE paperkey='" + DB.q(id,16) + "'");
            while (rs.next()) {
                boolean analysed = rs.getString(DB.analysed).equals("1");
                pdfLink += "&nbsp;&nbsp;&nbsp;<a href='/pdf?id=" + rs.getString(DB.md5) + "' class='menu'>PDF</a>";
                if (analysed) {
                    pdfLink += "&nbsp;<a href='/data?id=" + rs.getString(DB.md5) + "' class='menu'>Data</a>";
                }
            }
            if (pdfLink.equals("")) {
                pdfLink = "no PDF archived";
                noBibliography = "Paper not in archive - no bibliography";
            }
            rs.close();
            doPageHeader(out, pdfLink, "Home");
            rs = st.executeQuery("SELECT authors FROM authors WHERE paperkey='" + DB.q(id,16) + "' ORDER BY sequence");
            StringBuilder sb = new StringBuilder();
            while (rs.next()) {
                String a = rs.getString(1);
                sb.append("<a href='/author?name=" + a.replaceAll(" ","+") +
                          "'>" + a + "</a>;&nbsp;&nbsp;");
            }
            rs.close();
            rs = st.executeQuery("SELECT authors, email, title, year FROM papers p WHERE key='" + DB.q(id,16) + "'");
            if (!rs.next()) {
                out.println("No such paper");
                doTrailer(out);
                return;
            }
            String title = rs.getString(DB.title);
            if (title.startsWith("MD5: ")) {
                noCitations = "Paper title not established";
            }
            out.println("<div class='addButton'>");
            out.println("<a href='/home?add=" + id + "'>Add to home</a>");
            out.println("<a href='http://www.google.com/search?q=" + title.replaceAll("[ \n]","+") + "'>Google</a></div>");
            out.println("<div class='center'>");
            out.println("<span class='huge'>");
            out.println(title);
            out.println("<br/></span><span class='large'>");
            out.println(sb.length() == 0 ? rs.getString(DB.authors) : sb.toString());
            out.println("<br/></span><span class='large'><tt>");
            out.println(rs.getString(DB.email));
            out.println("</tt><br/></span>");
            out.println(rs.getString(DB.year));
            out.println("</div>");
            rs.close();
            paperListStart(out);
            showQuery(st, out,
                      "SELECT null as weight, f.md5, p.key, p.authors, p.title, p.year, t.tag, t.tagid, t.userid, t.paperkey FROM citations c JOIN papers p ON (c.cites=p.key and c.paper='" + DB.q(id,16) + "') LEFT JOIN pdffiles f ON (f.paperkey=p.key) LEFT JOIN tags t ON (t.paperkey=p.key) ORDER by p.authors, p.key, f.md5",
                      "Bibliography", noBibliography);
            showQuery(st, out,
                      "SELECT null as weight, f.md5, p.key, p.authors, p.title, p.year, t.tag, t.tagid, t.userid, t.paperkey FROM citations c JOIN papers p ON (c.cites='" + DB.q(id,16) + "' and c.paper=p.key) LEFT JOIN pdffiles f ON (f.paperkey=p.key) LEFT JOIN tags t ON (t.paperkey=p.key) ORDER BY p.year ASC, p.key, f.md5",
                      "<a href='/citations?id="+id+"'>Cited By</a>", noCitations);
            showQuery(st, out,
                      "SELECT f.md5, COUNT(p.key) as weight, p.key, p.authors, p.title, p.year, t.tag, t.tagid, t.userid, t.paperkey FROM citations c JOIN citations c2 ON (c.paper='" + DB.q(id,16) + "' and c.cites=c2.cites and c2.paper!=c.paper) JOIN papers p ON (c2.paper=p.key) LEFT JOIN pdffiles f ON (f.paperkey=p.key) LEFT JOIN tags t ON (t.paperkey=p.key) GROUP BY f.md5, p.key, p.authors, p.title, p.year, t.tag, t.tagid, t.userid, t.paperkey HAVING COUNT(p.key)>1 ORDER BY weight DESC, p.year DESC, p.key, f.md5",
                      "Papers with a similar bibliography", noBibliography);
            showQuery(st, out,
                      "SELECT f.md5, COUNT(p.key) as weight, p.key, p.authors, p.title, p.year,  t.tag, t.tagid, t.userid, t.paperkey FROM citations c JOIN citations c2 ON (c.cites='" + DB.q(id,16) + "' and c.paper=c2.paper and c.cites!=c2.cites) JOIN papers p ON (c2.cites=p.key) LEFT JOIN pdffiles f ON (f.paperkey=p.key) LEFT JOIN tags t ON (t.paperkey=p.key) GROUP BY f.md5, p.key, p.authors, p.title, p.year, t.tag, t.tagid, t.userid, t.paperkey HAVING COUNT(p.key)>1 ORDER BY weight DESC, p.year ASC, p.key, f.md5",
                      "Papers that appear in bibliographies citing this paper", noCitations);
            paperListEnd(out);
        } catch (SQLException e) {
            System.err.println("Failed to find paper " + id + " " + e);
            StackTraceElement[] ste = e.getStackTrace();
            for (int i = 0; i < ste.length; i++) {
                System.err.println(ste[i].toString());
            }
        } finally {
            try {
                if (rs != null) rs.close();
                if (st != null) st.close();
            } catch(Exception e) {
                System.err.println("Fuck..." + e);
            }
        }
        doTrailer(out);
    }

    private void showHome(PrintWriter out, Map<String,String[]> args, String userID, String cookie, String email) {
        try {
            int nFiles = 0;
            long kBytes = 0;
            String meta = "";
            Statement st = DB.connection.createStatement();
            ResultSet rs = st.executeQuery("SELECT SUM(filesize) as bytes, COUNT(filename) as nf FROM filequeue WHERE userid='" + DB.q(userID,16) + "'");
            if (rs.next()) {
                nFiles = rs.getInt("nf");
                kBytes = rs.getLong("bytes")/1024;
                if (nFiles != 0) {
                    meta = "<meta http-equiv='Refresh' content='10; url=/home'>";
                }
            }
            
            doHTMLHeader(out, "Home", "", meta);
            doPageHeader(out,"<a class='menu' href='/upload'>Upload papers</a>" + (email.equals("henkm@cs.bris.ac.uk")?"&nbsp;&nbsp;&nbsp;<a class='menu' href='/reprocess?id=all'>Reprocess all</a>":""), "Home",email);
            String[] add = args.get("add");
            if (add != null) {
                for (int i = 0; i < add.length; i++) {
                    st.executeUpdate("INSERT INTO userpapers (userid,paperkey,personalnotes,md5) VALUES ('" + userID + "','" + DB.q(add[i],DB.paperKeyMax) + "','','')"); // sequence auto increments
                }
            }
            add = args.get("addmd5");
            if (add != null) {
                for (int i = 0; i < add.length; i++) {
                    st.executeUpdate("INSERT INTO userpapers (userid,md5,personalnotes,paperkey) VALUES ('" + userID + "','" + DB.q(add[i],DB.md5Max) + "','','')"); // sequence auto increments
                }
            }
            String[] update = args.get("personalnotes");
            if (update != null) {             // fixme, this is no longer here.
                String id = args.get("id")[0];
                st.executeUpdate("UPDATE userpapers SET personalnotes='" + DB.q(update[0], 65536) + "' WHERE userid='" + userID + "' and paperKey='" + DB.q(id, DB.paperKeyMax) + "'");
            }
            
            String[] message = args.get("message");
            if (message != null) {
                for (int i = 0; i < message.length; i++) {
                    out.println("<p>" + message[i] + "</p>");
                }
            }

            if (nFiles != 0) {
                out.println("<p>At the moment, the system is processing " +
                            nFiles + " of your files with a combined size of " +
                            kBytes/1024 +"."+ kBytes%1024 + "MBytes</p>");
            }

            
			rs = st.executeQuery("SELECT count(*) FROM  userpapers up LEFT JOIN pdffiles f ON (f.md5=up.md5) LEFT JOIN papers p ON (p.key=f.paperkey) WHERE up.userid='" + DB.q(userID,16) + "'"); // fixme, repair duplicates with multiple PDF files.
            rs.next();
			int rowCount=rs.getInt(1);
			rs.close();

            out.println("<div class='cites'>");
            Pager pager = new Pager(out, rowCount, args.get("page"),"/home?");
            pager.header();

            // FIXME: Personal notes are dead. Long live personal notes.
            // Shoudl eb replaced with tags anyway?
            paperListStart(out);
            showQuery(st, out, 
                      "SELECT DISTINCT null as weight, p.title, up.personalnotes, up.md5, f.paperkey as key, p.year, p.authors, up.sequence, f.analysed, t.tag, t.tagid, t.userid, t.paperkey FROM  userpapers up LEFT JOIN pdffiles f ON (f.md5=up.md5) LEFT JOIN papers p ON (p.key=f.paperkey) LEFT JOIN tags t ON (t.paperkey = p.key) WHERE up.userid='" + DB.q(userID,16) + "' ORDER by sequence DESC "+pager.addendum,
                      "Papers", ("You can add papers to this page by " +
                                 "Uploading papers using the link in the "+
                                 "top-left-hand corner, or by searching " +
                                 "for papers that are in the database "+
                                 "and adding them to your home"));

            paperListEnd(out);
            pager.footer();
            out.print("</div>");
            st.close();
        } catch (SQLException e) {
            System.err.println("Failed to find paper  " + e);
        }
        doTrailer(out);
    }

    private void showCitations(PrintWriter out, Map<String,String[]> args, String email) {
        Vector<String> hows = new Vector<String>();
        Vector<String> authors = new Vector<String>();
        Vector<String> titles = new Vector<String>();
        String  id = args.get("id")[0];
        doHTMLHeader(out,id);
        doPageHeader(out, "", "Home");
        try {
            Statement st = DB.connection.createStatement();
            ResultSet rs = st.executeQuery("SELECT authors, title, howpublished FROM citations WHERE cites='" + DB.q(id,16) + "'");
            while(rs.next()) {
                authors.add(rs.getString("authors"));
                titles.add(rs.getString("title"));
                hows.add(rs.getString("howpublished"));
            }
            printVector(out, authors, "Authors");
            printVector(out, titles, "Titles");
            printVector(out, hows, "Details");
            doTrailer(out);
            st.close();
        } catch (SQLException e) {
            System.err.println("Failed to find paper " + id + " " + e);
        }
        doTrailer(out);
    }

    public void printVector(PrintWriter out, Vector<String> x, String y) {
        out.println("<h2>" + y + "</h2><ul>");
        for(int i = 0; i <x.size(); i++) {
            out.println("<li>" + x.get(i) + "</li>");
        }
        out.println("</ul>");
    }

    private void showWelcome(PrintWriter out, boolean authorised) {
        String nCitations = "", nPapers = "", nAuthors = "";
        int nPDFanalysed = 0, nPDFbad = 0, nPDF = 0;
        doHTMLHeader(out,"Welcome");
        doPageHeader(out, "", authorised ? "Home" : "Login");
          /* Null-Pointer */
          if(DB.connection==null){
               System.err.println("Cannot connect to DB");
                 out.println("<h2>Welcome to paperBase</h2>"+
                 "<p>Unfortunately there is a database problem at present - </p>"+
                 "<p>Please contact the system administrator</p>");
                 return;
           }

        try {
            Statement st = DB.connection.createStatement();
            ResultSet rs = st.executeQuery("SELECT count(md5) as c, analysed FROM pdffiles GROUP BY analysed");
            while(rs.next()) {
                if(rs.getString("analysed").equals("1")) {
                    nPDFanalysed = rs.getInt("c");
                } else {
                    nPDFbad = rs.getInt("c");
                }
            }
            nPDF = nPDFbad + nPDFanalysed;
            rs = st.executeQuery("SELECT count(*) as c FROM citations");
            if(rs.next()) {
                nCitations = rs.getString("c");
            }
            rs = st.executeQuery("SELECT count(*) as c FROM papers");
            if(rs.next()) {
                nPapers = rs.getString("c");
            }
            rs = st.executeQuery("SELECT count(*) as c FROM authors");
            if(rs.next()) {
                nAuthors = rs.getString("c");
            }
            out.println("<h2>Welcome to paperBase</h2>" +
                        "<p>This archive contains " + nPDF +
                        " PDF files; " + nPDFanalysed + " of these files " +
                        " have been parsed and contain " + nCitations +
                        " citations to " + nPapers + " distinct papers by "+
                        "<a href='/allauthors'>"+nAuthors+" authors</a>.</p>" +
                        "<p>in order to use it, use the search box in the top " +
                        "right hand corner of the page, or go to your " +
                        "personal home page where you can upload your own " +
                        "archive of PDF files.</p>");
            if (authorised) {
            } else {
                String users = "";
                rs = st.executeQuery("SELECT (count(userid)+1) as c FROM users WHERE password<>''");
                if(rs.next()) {
                    users = rs.getString("c");
                }
                if (users.endsWith("2")) {
                    if (users.endsWith("12")) {
                        users += "st";
                    } else {
                        users += "nd";
                    }
                } else if (users.endsWith("3")) {
                    if (users.endsWith("13")) {
                        users += "st";
                    } else {
                        users += "rd";
                    }
                } else {
                    users += "st";
                }
                out.println("<p>Before you can upload papers you must " +
                            "<a href='/login'>register yourself with " +
                            "paperBase</a>. Registration is free; if you " +
                    "register, you would be the " + users + " user.");
            }
            doTrailer(out);
            st.close();
        } catch (SQLException e) {
            System.err.println("Failed to get basic stats " + e);
        }
        doTrailer(out);
    }



    private void showData(PrintWriter out, Map<String,String[]> args, String email) {
        String  id = args.get("id")[0];
        try {
            Statement st = DB.connection.createStatement();
            ResultSet rs;
            String meta = "";
            doHTMLHeader(out,id,"",meta);
            doPageHeader(out,
                         "&nbsp;&nbsp;&nbsp;<a class='menu' href='/pdf?id=" + id+
                         "'>PDF</a>&nbsp;<a class='menu' href='/text?id=" + id+
                         "'>Txt</a>&nbsp;<a class='menu' href='/reprocess?id="+id+
                         "'>Reprocess</a>", "Home");

            rs = st.executeQuery("SELECT analysed, data FROM pdffiles WHERE md5='" + DB.q(id,32) + "'");
            if (rs.next() && rs.getString(DB.analysed).equals("1")) {
                out.print(rs.getString(DB.data));
            } else {
                out.println("This paper has not been analysed");
            }
            out.println("</div>");
            doTrailer(out);
            st.close();
        } catch (SQLException e) {
            System.err.println("Failed to find paper " + id + " " + e);
        }
        doTrailer(out);
    }

    private void showSearch(PrintWriter out, Map<String,String[]> args, String email) {
        String queryParameter = args.get("query")[0];
        String query = Paper.cleanUp(queryParameter);

    	QueryBuilder aQuery=new QueryBuilder();
		// hardcoded for your pleasure ^_~
        String newQuery=aQuery.makeSQL(queryParameter,"f.flattitle","p.authors","p.year");

		// if rowCount is bigger than whatever our display threshold is, we ought to limit it (LIMIT x OFFSET y)	
		
        doHTMLHeader(out,"Search results", "document.search.query.value=\""+ queryParameter.replaceAll("\"","'")+"\"; document.search.query.focus();document.search.query.select();");
        doPageHeader(out,"", "Home");
        try {
            Statement st = DB.connection.createStatement();
			if(newQuery!=""){
				ResultSet rc=st.executeQuery("SELECT count(p.key) AS rowcount from flattitles f, papers p "+newQuery + "and f.paperkey=p.key ");
				rc.next();
				int rowCount= rc.getInt("rowcount") ;
				rc.close();
                
                Pager pager= new Pager(out, rowCount, args.get("page"),
                                       "search?query="+queryParameter+"&amp;");
                pager.header(
                    "No papers found ",
                    "(search terms used were: <i>"+aQuery.safeSearchTermPrint()+"</i>)");
                paperListStart(out);
                showQuery(st, out,
                          "SELECT pf.md5, p.key, p.authors, p.title, p.year, null as weight, t.tag, t.tagid, t.userid, t.paperkey " +
                          "FROM flattitles f, papers p LEFT JOIN pdffiles pf ON pf.paperkey=p.key LEFT JOIN tags t ON (t.paperkey=p.key)"+newQuery + " and "+
                          " f.paperkey=p.key ORDER BY p.year, p.key, pf.md5 "+pager.addendum,
                          "Results...","");
                paperListEnd(out);
                
                pager.footer();
            	st.close();
			}else{
				out.println("No search query was given!");
				out.println(aQuery.queryHelp());
			}
        } catch (SQLException e) {
            System.err.println("Failed to find paper " + query + " " + e);
        }
        doTrailer(out);
    }

    private void showAuthor(PrintWriter out, Map<String,String[]> args, String email) {
        String name = args.get("name")[0];

        doHTMLHeader(out,"Author results");
        doPageHeader(out,"", "Home");
        try {
            Statement st = DB.connection.createStatement();
            paperListStart(out);
            showQuery(st, out,
                      "SELECT null as weight, p.key, p.authors, p.title, p.year, MAX(f.md5) as md5, t.tag, t.tagid, t.userid, t.paperkey "+
                      "FROM authors a, papers p LEFT JOIN pdffiles f ON (f.paperkey=p.key) LEFT JOIN tags t ON (t.paperkey=p.key) WHERE " +
                      "a.authors = '" + DB.q(name,200) + "' and a.paperkey=p.key " +
                      "GROUP BY a.sequence, p.key, p.authors, p.title, p.year, t.tag, t.tagid, t.userid, t.paperkey, f.md5 ORDER BY a.sequence, p.year, p.key, f.md5",
                      "Papers by " + name, "No papers found. Odd...");
            paperListEnd(out);
            st.close();
        } catch (SQLException e) {
            System.err.println("Failed to find paper " + name + " " + e);
        }
        doTrailer(out);
    }

    private static class AuthorAnalysis implements Comparable {
        String name; 
        int references;
        int files;
        final int base = 1;

        AuthorAnalysis(String n) {
            name = n;
        }

        public int compareTo(Object y) {
            AuthorAnalysis x = (AuthorAnalysis) y;
            double r0 = ((double)files+base)/(references+1);
            double r1 = ((double)x.files+base)/(x.references+1);
            if (r0 > r1) return 1;
            if (r0 < r1) return -1;
            return 0;
        }
    }

    private void showAllAuthors(PrintWriter out, Map<String,String[]> args, String email) {
        Vector<AuthorAnalysis> authors = new Vector<AuthorAnalysis>();

        doHTMLHeader(out,"Author results");
        doPageHeader(out,"", "Home");
        try {
            Statement st = DB.connection.createStatement();
            String lastName = "";
            AuthorAnalysis author = null;
            ResultSet rs = st.executeQuery(
                "SELECT a.authors, p.key, a.sequence, MAX(f.md5) as md5 "+
                "FROM authors a, papers p LEFT JOIN pdffiles f ON (f.paperkey=p.key) WHERE " +
                "a.paperkey=p.key " +
                "GROUP BY a.authors, a.sequence, p.key");
            while (rs.next()) {
                String name = rs.getString(DB.authors);
                if (!name.equals(lastName)) {
                    lastName = name;
                    author = new AuthorAnalysis(name);
                    authors.add(author);
                }
                author.references++;
                String md5 = rs.getString(DB.md5);
                if (md5 != null && !md5.equals("")) {
                    author.files++;
                }
            }
            rs.close();
            Collections.sort(authors);
            out.println("<ul>");
            for (Iterator<AuthorAnalysis> i = authors.iterator(); i.hasNext();) {
                author = i.next();
                out.println("<li>" + author.files + " pdf files " + author.references + " references for <a href='/author?name=" + author.name.replaceAll(" ","+")+"'>" + author.name + "</a></li>");
            }
            out.println("</ul>");
            
            st.close();
        } catch (SQLException e) {
            System.err.println("Failed to find paper " + name + " " + e);
        }
        doTrailer(out);
    }


    private boolean doLogin(HttpServletResponse resp, String email, String password) throws IOException {
        String cookie = Authorisation.cookieForPassword(email, password);
        if (cookie != null) {
            Cookie auth = new Cookie("auth", cookie);
            Cookie mail = new Cookie("email", email);
            auth.setMaxAge(0x7fffffff);
            mail.setMaxAge(0x7fffffff);
            resp.addCookie(auth);
            resp.addCookie(mail);
            resp.sendRedirect("/home");
            return true;
        }
        return false;
    }

    private void showLogin(HttpServletResponse resp, Map<String,String[]> args,
                           String cookieMail) throws IOException {
        String[] email = null;
        String[] password = null;
        String extra = "";
        email    = args.get("email");
        password = args.get("password");
        if (email != null && password != null) {
            if (doLogin(resp, email[0], password[0])) {
                return;
            }
            extra = " email or password incorrect";
        }
        PrintWriter out = resp.getWriter();
        if (cookieMail == null) {
            cookieMail = "";
        }
        resp.setContentType("text/html");
        doHTMLHeader(out,"Login", "document.login.password.focus();");
        doPageHeader(out,"Login" + extra, null);
        out.println("<h2>Login</h2>");
        out.println("<form action='/login' name='login' method='get'><table><tr>");
        out.println("<td>E-mail address:</td>"); //fixme, post not get
        out.println("<td><input type='text' name='email' size='20' value='" + cookieMail + "'/></td>");
        out.println("</tr><tr>");
        out.println("<td>Password:</td>");
        out.println("<td><input type='password' name='password' size='20'/></td>");
        out.println("</tr><tr>");
        out.println("<td></td>");
        out.println("<td><input type='submit' value='login'/></td>");
        out.println("</tr></table></form>");
        out.println("<h2>Register yourself</h2>");
        out.println("<form action='/registermail' method='get'><table><tr>");
        out.println("<td>E-mail address:</td>");
        out.println("<td><input type='text' name='email' size='20'/></td>");
        out.println("</tr><tr>");
        out.println("<td></td>");
        out.println("<td><input type='submit' value='Register me'/></td>");
        out.println("</tr></table></form>");
        out.println("<h2>Forgotten my password</h2>");
        out.println("<form action='/registermail' method='get'><table><tr>");
        out.println("<td>E-mail address:</td>");
        out.println("<td><input type='text' name='email' size='20' value='" + cookieMail + "'/></td>");
        out.println("</tr><tr>");
        out.println("<td></td>");
        out.println("<td><input type='submit' value='Reset my password'/></td>");
        out.println("</tr></table></form>");
        doTrailer(out);
    }

    private void showRegisterMail(HttpServletRequest req, HttpServletResponse resp, Map<String,String[]> args) throws IOException {
        String email = args.get("email")[0];
        String cookie = Authorisation.resetPassword(email);
        if (cookie != null) {
            try {
                String url =req.getScheme() + "://" + req.getServerName();
                int p = req.getServerPort();
                if (p != 80 && p != 443) {
                    url += ":" + p;
                }
                url += "/register?cookie=" + cookie + "&email=" + email;//fixme, needs encoding
                if (false) { // temp disable registration...
                    String[] mailcommand = {"/usr/lib/sendmail", email};
                    Process mailer = Runtime.getRuntime().exec(mailcommand);
                    PrintStream mail = new PrintStream(mailer.getOutputStream());
                    mail.println("Subject: paperBase password");
                    mail.println("Reply-To: no-reply@paperBase.com");
                    mail.println("From: no-reply@paperBase.com");
                    mail.println("We have had a request to (re)set the password belonging to this");
                    mail.println("email address. If you visit the URL below you can set your password");
                    mail.println("  <"+ url + ">");
                    mail.println(".");
                    mail.close();
                    resp.sendRedirect("/register"); // prevents reloading.
                } else {
                    resp.sendRedirect(url);
                }
            } catch (Exception err) {
                System.err.println("FATAL: " + err.getMessage());
            }
        }
        sendError(resp, "Failed registration request");
    }

    public void sendError(HttpServletResponse resp, String x) throws IOException {
        PrintWriter out = resp.getWriter();
        doHTMLHeader(out,"Registration");
        doPageHeader(out,"Register", x);
        doTrailer(out);
    }

    private void showRegister(PrintWriter out, Map<String,String[]> args) throws IOException {
        doHTMLHeader(out,"Registration", "document.details.password.focus();");
        doPageHeader(out,"Register", null);
        String cookie = null;
        String email = null;
        String[] c = args.get("cookie");
        String[] e = args.get("email");
        if (c == null || e == null) {
            out.println("<h2>Registration</h2>");
            out.println("<p>We have sent you an email. You can set your");
            out.println("password by following the link in this email.</p>");
            out.println("<p>Please check your spam-box if the email does");
            out.println("not arrive within a couple of minutes.</p>");
        } else {
            cookie = c[0];
            email = e[0];
            Authorisation a = Authorisation.loadOnReset(cookie);
            if (a == null) {
                out.print("bad request " + cookie);
                return;
            }
            out.println("<h2>Set your password</h2>" +
                        "<form name='details' action='/registerupdate' method='get'><table><tr>" +
                        "<td>E-mail address:</td>" +       //fixme, post not get
                        "<td><input type='text' name='email' size='20' readonly value='" + email + "'/>" +
                        "<input type='hidden' name='cookie' size='20' value='" + cookie + "'/></td>" +
                        "</tr><tr>" +
                        "<td>Pick a password:</td>" +
                        "<td><input type='password' name='password' value='' size='20'/></td>" +
                        "</tr><tr class='optional'>" +
                        "<td>Given name:</td>" +
                        "<td><input type='text' name='givenname' value='"+a.givenName+"' size='60'/></td>" +
                        "</tr><tr class='optional'>" +
                        "<td>Surname:</td>" +
                        "<td><input type='text' name='surname' value='"+a.surname+"' size='60'/></td>" +
                        "</tr><tr class='optional'>" +
                        "<td>Affiliation:</td>" +
                        "<td><input type='text' name='affiliation' value='"+a.affiliation+"' size='60'/></td>" +
                        "</tr><tr>" +
                        "<td></td>" +
                        "<td><input type='submit' value='Update'/></td>" +
                        "</tr></table></form>");
        }
        doTrailer(out);
    }

    private void showRegisterUpdate(HttpServletResponse resp, Map<String,String[]> args) throws IOException {
        String[] e = args.get("email");
        String[] c = args.get("cookie");
        String[] p = args.get("password");
        String[] g = args.get("givenname");
        String[] s = args.get("surname");
        String[] af= args.get("affiliation");
        Authorisation a = Authorisation.loadOnReset(c[0]);
        if (a == null) {
            sendError(resp,"Bad request " + c[0]);
            return;
        }
        if (g != null && !g[0].equals("")) {
            a.givenName = g[0];
        }
        if (s != null && !s[0].equals("")) {
            a.surname = s[0];
        }
        if (af != null && !af[0].equals("")) {
            a.affiliation = af[0];
        }
        a.commitEntry(p[0]);
        if(doLogin(resp, e[0], p[0])) {
            return;
        }
    }












    private void showUpload(PrintWriter out, String email) throws IOException {
        doHTMLHeader(out,"Upload", "document.upload.file.focus();");
        doPageHeader(out,"", "Home");
        out.println("<h2>Upload</h2>"+
                    "From this page you can upload files. You can upload "+
                    "PDF files, Postscript files, gzipped postscript files, "+
                    "bibtex files, "+
                    "zip archives of any of the above, and tar balls. "+
                    "Alternatively, you can submit a URL that will "+
                    "be explored. If you submit large tar balls, please "+
                    "be patient while the file is being uploaded to the "+
                    "server. All files are processed in the background, "+
                    "hence it may be a while until your files are present."+
                    "Your home page gives you the current status."+
                    "" +
                    "<table><tr>" +
                    "<form name='upload' action='/doupload' method='post' enctype='multipart/form-data'>" +
                    "<td><input class='update' type='file' name='file' size='50'/></td>" +
                    "<td><input type='checkbox' name='copyright' value='true'/> Copyrighted</td>" +
                    "<td><input class='update' type='submit' value='Submit File'/></td>" +
                    "</tr></form>" +
                    "<form action='/dourl' method='get'><tr>" +
                    "<td><input class='update' type='text' name='url' size='60'/></td>" +
                    "<td><input type='checkbox' name='copyright' value='true'/> Copyrighted</td>" +
                    "<td><input class='update' type='submit' value='Submit URL'/></td>" +
                    "</tr></form></table>");
        doTrailer(out);
    }

    private void doUpload(HttpServletRequest req, HttpServletResponse resp,
                          String userID) throws IOException {
        UpLoad upLoader = new UpLoad(req.getInputStream());
        upLoader.fieldString("copyright");
        upLoader.fieldFile("file");
        upLoader.process();
        boolean copyrighted =upLoader.getParameter("copyright").equals("true");
        batchProcessor.addFile(userID, upLoader.getOriginal("file"),
                               copyrighted, upLoader.getFile("file"),
                               upLoader.getMd5("file"));
        long bytes = upLoader.getFileLength("file");
        resp.sendRedirect("/home?message=Thank+you,+processing+"+
                          (bytes/1024/1024) +"." + (bytes/1024 % 1024) +"Mb");
    }

    private void doURL(String userID, HttpServletResponse resp,
                       Map<String,String[]> args) throws IOException {
        String[] url = args.get("url");
        batchProcessor.addURL(userID, url[0], false, url[0], 1);
        resp.sendRedirect("/home?message=Thank+you,+processing+URL");
    }

}
